home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / CLASSSRC.PAK / MSGTHRED.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  5KB  |  215 lines

  1. //----------------------------------------------------------------------------
  2. // Borland WinSys Library
  3. // Copyright (c) 1995, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   5.7  $
  6. //
  7. // Implementation of class TMsgThread. This implements basic behavior for
  8. // threads that own message queues, including mutex locking for the queue
  9. //----------------------------------------------------------------------------
  10. #include <winsys/pch.h>
  11. #if !defined(WINSYS_MSGTHRED_H)
  12. # include <winsys/msgthred.h>
  13. #endif
  14.  
  15. DIAG_DEFINE_GROUP(MsgThreads,1,0);
  16.  
  17. //
  18. // Attach to the current running thread. This is often the initial process
  19. // thread, or even the only thread for non-threaded systems.
  20. //
  21. #if defined(BI_MULTI_THREAD_RTL)  // No threads without RTL support
  22. TMsgThread::TMsgThread(TCurrent c)
  23. :
  24.   TThread(c),
  25.   UseMutex(false),  // Default for primary thread is single-threaded
  26. #else
  27. TMsgThread::TMsgThread(TCurrent /*c*/)
  28. :
  29. #endif
  30.   MessageLoopResult(0),
  31.   BreakMessageLoop(false),
  32.   LoopRunning(false)
  33. {
  34. }
  35.  
  36. #if defined(BI_MULTI_THREAD_RTL)  // No real threads without RTL support
  37. //
  38. // Create a thread.
  39. // The thread is in a paused-state.
  40. //
  41. TMsgThread::TMsgThread()
  42. :
  43.   TThread(),
  44.   MessageLoopResult(0),
  45.   BreakMessageLoop(false),
  46.   LoopRunning(false),
  47.   UseMutex(true)  // Default for created thread is multi-threaded
  48. {
  49. }
  50. #endif
  51.  
  52. //
  53. // General message loop: retrieve and process messages from the thread's
  54. // message queue using PumpWaitingMessages() until BreakMessageLoop becomes
  55. // true. Catch exceptions to post a quit message and cleanup before resuming.
  56. //
  57. // Call IdleAction() when there are no messages
  58. //
  59. int
  60. TMsgThread::MessageLoop()
  61. {
  62.   long idleCount = 0;
  63.   MessageLoopResult = 0;
  64.   try {
  65.     while (!BreakMessageLoop) {      
  66.       if (!IdleAction(idleCount++))
  67.         ::WaitMessage();             // allow system to go idle
  68.       if (PumpWaitingMessages())     // pumps any waiting messages
  69.         idleCount = 0;
  70.     }
  71.   }
  72.   catch (...) {
  73.     ::PostQuitMessage(-1);
  74.     BreakMessageLoop = false;
  75.     throw;
  76.   }
  77.   BreakMessageLoop = false;
  78.   return MessageLoopResult;
  79. }
  80.  
  81. //
  82. // Called each time there are no messages in the queue. Idle count is
  83. // incremented each time, & zeroed when messages are pumped. Return
  84. // whether or not more processing needs to be done.
  85. //
  86. bool
  87. #if defined(__TRACE)
  88. TMsgThread::IdleAction(long idleCount)
  89. #else
  90. TMsgThread::IdleAction(long /*idleCount*/)
  91. #endif
  92. {
  93.   TRACEX(MsgThreads, 1, "TMsgThread::IdleAction() called @" << (void*)this <<
  94.                         " idleCount " << idleCount);
  95.   return false;
  96. }
  97.  
  98. //
  99. // Called for each message that is pulled from the queue, to perform all
  100. // translation & dispatching.
  101. //
  102. // Return true to drop out of pump
  103. //
  104. bool
  105. TMsgThread::ProcessMsg(MSG& msg)
  106. {
  107.   // Translate the message & dispatch it.TMsgThread
  108.   //
  109.   ::TranslateMessage(&msg);
  110.   ::DispatchMessage(&msg);
  111. //  ResumeThrow();
  112.  
  113.   return false;
  114. }
  115.  
  116. //
  117. // Inner message loop: retrieve and processe messages from the OWL
  118. // application's message queue until it is empty. Set BreakMessageLoop if a
  119. // WM_QUIT passes thru.
  120. //
  121. // Call ProcessAppMsg() for each message to allow special pre-handling of the
  122. // message
  123. //
  124. bool
  125. TMsgThread::PumpWaitingMessages()
  126. {
  127.   MSG  msg;
  128.   bool foundOne = false;
  129.  
  130.   while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
  131.     foundOne = true;
  132.     if (msg.message == WM_QUIT) {
  133.       BreakMessageLoop = true;
  134.       MessageLoopResult = msg.wParam;
  135.       ::PostQuitMessage(msg.wParam);  // make sure all loops exit
  136.       break;
  137.     }
  138.     if (ProcessMsg(msg))
  139.       return true;
  140.   }
  141.   return foundOne;
  142. }
  143.  
  144. //
  145. // Flush all real messages from the message queue
  146. //
  147. void
  148. TMsgThread::FlushQueue()
  149. {
  150.   MSG msg;
  151.   while (::PeekMessage(&msg,0,0,0,PM_NOYIELD|PM_REMOVE)
  152.          && msg.message != WM_PAINT)
  153.     ;
  154. }
  155.  
  156. //
  157. // Run this message thread, return when the message queue quits
  158. //
  159. // Initialize instances. Run the thread's message loop. Each of the virtual
  160. // functions called are expected to throw an exception if there is an error.
  161. //
  162. // Exceptions that are not handled, i.e. status remains non-zero, are
  163. // propagated out of this function. Msg queue is still flushed & TermInstance
  164. // called.
  165. //
  166. int
  167. TMsgThread::Run()
  168. {
  169.   int status;
  170.   try {
  171.     InitInstance();
  172.     LoopRunning = true;
  173.     status = MessageLoop();
  174.   }
  175.   catch (...) {
  176.     LoopRunning = false;
  177.     FlushQueue();
  178.     TermInstance(status);
  179.     throw;
  180.   }
  181.  
  182.   LoopRunning = false;
  183.   FlushQueue();
  184.   return TermInstance(status);
  185. }
  186.  
  187. //
  188. // Handle initialization for each executing instance of the msg thread
  189. // Derived classes can override this to perform initialization for each
  190. // instance.
  191. //
  192. void
  193. TMsgThread::InitInstance()
  194. {
  195.   TRACEX(MsgThreads, 1, "TMsgThread::InitInstance() called @" << (void*)this);
  196.  
  197.   // Override to perform initialization prior to running
  198.   // Call TMsgThread::InitInstance() before body
  199. }
  200.  
  201. //
  202. // Handle termination for each executing instance of the msg thread. Called
  203. // at the end of a Run() with the final return status.
  204. //
  205. int
  206. TMsgThread::TermInstance(int status)
  207. {
  208.   TRACEX(MsgThreads, 1, "TMsgThread::TermInstance() called @" << (void*)this);
  209.  
  210.   // Override to perform termination cleanup after running
  211.   // Call TMsgThread::TermInstance(status) after body
  212.  
  213.   return status;
  214. }
  215.